home *** CD-ROM | disk | FTP | other *** search
/ Programming an RTS Game with Direct3D / Programming an RTS Game with Direct3D.iso / Examples / Chapter 5 / Example 5.9 / terrain.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2006-06-29  |  19.2 KB  |  724 lines

  1. #include "terrain.h"
  2. #include "camera.h"
  3.  
  4. const DWORD TERRAINVertex::FVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX2;
  5.  
  6. //////////////////////////////////////////////////////////////////////////////////////////
  7. //                                    PATCH                                                //
  8. //////////////////////////////////////////////////////////////////////////////////////////
  9.  
  10. PATCH::PATCH()
  11. {
  12.     m_pDevice = NULL;
  13.     m_pMesh = NULL;
  14. }
  15. PATCH::~PATCH()
  16. {
  17.     Release();
  18. }
  19.  
  20. void PATCH::Release()
  21. {
  22.     if(m_pMesh != NULL)
  23.         m_pMesh->Release();
  24.     m_pMesh = NULL;
  25. }
  26.  
  27. HRESULT PATCH::CreateMesh(TERRAIN &ter, RECT source, IDirect3DDevice9* Dev)
  28. {
  29.     if(m_pMesh != NULL)
  30.     {
  31.         m_pMesh->Release();
  32.         m_pMesh = NULL;
  33.     }
  34.  
  35.     try
  36.     {
  37.         m_pDevice = Dev;
  38.         m_mapRect = source;
  39.  
  40.         int width = source.right - source.left;
  41.         int height = source.bottom - source.top;
  42.         int nrVert = (width + 1) * (height + 1);
  43.         int nrTri = width * height * 2;
  44.  
  45.         if(FAILED(D3DXCreateMeshFVF(nrTri, nrVert, D3DXMESH_MANAGED, TERRAINVertex::FVF, m_pDevice, &m_pMesh)))
  46.         {
  47.             debug.Print("Couldn't create mesh for PATCH");
  48.             return E_FAIL;
  49.         }
  50.  
  51.         m_BBox.max = D3DXVECTOR3(-10000.0f, -10000.0f, -10000.0f);
  52.         m_BBox.min = D3DXVECTOR3(10000.0f, 10000.0f, 10000.0f);
  53.  
  54.         //Create vertices
  55.         TERRAINVertex* ver = 0;
  56.         m_pMesh->LockVertexBuffer(0,(void**)&ver);
  57.         for(int z=source.top, z0 = 0;z<=source.bottom;z++, z0++)
  58.             for(int x=source.left, x0 = 0;x<=source.right;x++, x0++)
  59.             {
  60.                 MAPTILE *tile = ter.GetTile(x, z);
  61.  
  62.                 D3DXVECTOR3 pos = D3DXVECTOR3(x, tile->m_height, -z);
  63.                 D3DXVECTOR2 alphaUV = D3DXVECTOR2(x / (float)ter.m_size.x, z / (float)ter.m_size.y);        //Alpha UV
  64.                 D3DXVECTOR2 colorUV = alphaUV * 8.0f;                                                    //Color UV
  65.                 ver[z0 * (width + 1) + x0] = TERRAINVertex(pos, alphaUV, colorUV);
  66.  
  67.                 //Calculate bounding box bounds...
  68.                 if(pos.x < m_BBox.min.x)m_BBox.min.x = pos.x;
  69.                 if(pos.x > m_BBox.max.x)m_BBox.max.x = pos.x;
  70.                 if(pos.y < m_BBox.min.y)m_BBox.min.y = pos.y;
  71.                 if(pos.y > m_BBox.max.y)m_BBox.max.y = pos.y;
  72.                 if(pos.z < m_BBox.min.z)m_BBox.min.z = pos.z;
  73.                 if(pos.z > m_BBox.max.z)m_BBox.max.z = pos.z;
  74.             }
  75.         m_pMesh->UnlockVertexBuffer();
  76.  
  77.         //Calculate Indices
  78.         WORD* ind = 0;
  79.         m_pMesh->LockIndexBuffer(0,(void**)&ind);    
  80.         int index = 0;
  81.  
  82.         for(int z=source.top, z0 = 0;z<source.bottom;z++, z0++)
  83.             for(int x=source.left, x0 = 0;x<source.right;x++, x0++)
  84.             {
  85.                 //Triangle 1
  86.                 ind[index++] =   z0   * (width + 1) + x0;
  87.                 ind[index++] =   z0   * (width + 1) + x0 + 1;
  88.                 ind[index++] = (z0+1) * (width + 1) + x0;        
  89.  
  90.                 //Triangle 2
  91.                 ind[index++] = (z0+1) * (width + 1) + x0;
  92.                 ind[index++] =   z0   * (width + 1) + x0 + 1;
  93.                 ind[index++] = (z0+1) * (width + 1) + x0 + 1;
  94.             }
  95.  
  96.         m_pMesh->UnlockIndexBuffer();
  97.  
  98.         //Set Attributes
  99.         DWORD *att = 0, a = 0;
  100.         m_pMesh->LockAttributeBuffer(0,&att);
  101.         memset(att, 0, sizeof(DWORD)*nrTri);
  102.         m_pMesh->UnlockAttributeBuffer();
  103.  
  104.         //Compute normals
  105.         D3DXComputeNormals(m_pMesh, NULL);
  106.     }
  107.     catch(...)
  108.     {
  109.         debug.Print("Error in PATCH::CreateMesh()");
  110.         return E_FAIL;
  111.     }
  112.  
  113.     return S_OK;
  114. }
  115.  
  116. void PATCH::Render()
  117. {
  118.     //Draw mesh
  119.     if(m_pMesh != NULL)
  120.         m_pMesh->DrawSubset(0);
  121. }
  122.  
  123. //////////////////////////////////////////////////////////////////////////////////////////
  124. //                                    TERRAIN                                                //
  125. //////////////////////////////////////////////////////////////////////////////////////////
  126.  
  127. TERRAIN::TERRAIN()
  128. {
  129.     m_pDevice = NULL;
  130.     m_pMapTiles = NULL;
  131. }
  132.  
  133. void TERRAIN::Init(IDirect3DDevice9* Dev, INTPOINT _size)
  134. {
  135.     m_pDevice = Dev;
  136.     m_size = _size;
  137.     m_pHeightMap = NULL;
  138.  
  139.     if(m_pMapTiles != NULL)    //Clear old maptiles
  140.         delete [] m_pMapTiles;
  141.  
  142.     //Create maptiles
  143.     m_pMapTiles = new MAPTILE[m_size.x * m_size.y];
  144.     memset(m_pMapTiles, 0, sizeof(MAPTILE)*m_size.x*m_size.y);
  145.  
  146.     //Clear old textures
  147.     for(int i=0;i<m_diffuseMaps.size();i++)
  148.         m_diffuseMaps[i]->Release();
  149.     m_diffuseMaps.clear();
  150.  
  151.     //Load textures
  152.     IDirect3DTexture9* grass = NULL, *mount = NULL, *snow = NULL;
  153.     if(FAILED(D3DXCreateTextureFromFile(Dev, "textures/grass.jpg", &grass)))debug.Print("Could not load grass.jpg");
  154.     if(FAILED(D3DXCreateTextureFromFile(Dev, "textures/mountain.jpg", &mount)))debug.Print("Could not load mountain.jpg");
  155.     if(FAILED(D3DXCreateTextureFromFile(Dev, "textures/snow.jpg", &snow)))debug.Print("Could not load snow.jpg");
  156.     m_diffuseMaps.push_back(grass);
  157.     m_diffuseMaps.push_back(mount);
  158.     m_diffuseMaps.push_back(snow);
  159.     m_pAlphaMap = NULL;
  160.  
  161.     //Load pixelshader
  162.     m_terrainPS.Init(Dev, "Shaders/terrain.ps", PIXEL_SHADER);
  163.  
  164.     //Create white material    
  165.     m_mtrl.Ambient = m_mtrl.Specular = m_mtrl.Diffuse  = D3DXCOLOR(0.5f, 0.5f, 0.5f, 1.0f);
  166.     m_mtrl.Emissive = D3DXCOLOR(0.0f, 0.0f, 0.0f, 1.0f);
  167.  
  168.     GenerateRandomTerrain(9);
  169. }
  170.  
  171. void TERRAIN::Release()
  172. {
  173.     for(int i=0;i<m_patches.size();i++)
  174.         if(m_patches[i] != NULL)
  175.             m_patches[i]->Release();
  176.  
  177.     m_patches.clear();
  178.  
  179.     if(m_pHeightMap != NULL)
  180.     {
  181.         m_pHeightMap->Release();
  182.         delete m_pHeightMap;
  183.         m_pHeightMap = NULL;
  184.     }
  185.  
  186.     m_objects.clear();
  187. }
  188.  
  189. void TERRAIN::GenerateRandomTerrain(int numPatches)
  190. {
  191.     try
  192.     {
  193.         Release();
  194.  
  195.         //Create two heightmaps and multiply them
  196.         m_pHeightMap = new HEIGHTMAP(m_size, 10.0f);
  197.         HEIGHTMAP hm2(m_size, 2.0f);
  198.  
  199.         m_pHeightMap->CreateRandomHeightMap(rand()%2000, 1.0f, 0.7f, 8);
  200.         hm2.CreateRandomHeightMap(rand()%2000, 2.5f, 0.8f, 3);
  201.  
  202.         hm2.Cap(hm2.m_maxHeight * 0.4f);
  203.  
  204.         *m_pHeightMap *= hm2;
  205.         hm2.Release();
  206.         
  207.         //Add objects
  208.         HEIGHTMAP hm3(m_size, 1.0f);
  209.         hm3.CreateRandomHeightMap(rand()%1000, 5.5f, 0.9f, 7);
  210.  
  211.         for(int y=0;y<m_size.y;y++)
  212.             for(int x=0;x<m_size.x;x++)
  213.             {
  214.                 if(m_pHeightMap->GetHeight(x, y) == 0.0f && hm3.GetHeight(x, y) > 0.7f && rand()%6 == 0)
  215.                     AddObject(0, INTPOINT(x, y));    //Tree
  216.                 else if(m_pHeightMap->GetHeight(x, y) >= 1.0f && hm3.GetHeight(x, y) > 0.9f && rand()%20 == 0)
  217.                     AddObject(1, INTPOINT(x, y));    //Stone
  218.             }
  219.  
  220.         hm3.Release();
  221.  
  222.         InitPathfinding();
  223.         CreatePatches(numPatches);
  224.         CalculateAlphaMaps();
  225.     }
  226.     catch(...)
  227.     {
  228.         debug.Print("Error in TERRAIN::GenerateRandomTerrain()");
  229.     }
  230. }
  231.  
  232. void TERRAIN::CreatePatches(int numPatches)
  233. {
  234.     try
  235.     {
  236.         //Clear any old m_patches
  237.         for(int i=0;i<m_patches.size();i++)
  238.             if(m_patches[i] != NULL)
  239.                 m_patches[i]->Release();
  240.         m_patches.clear();
  241.  
  242.         //Create new patches
  243.         for(int y=0;y<numPatches;y++)
  244.             for(int x=0;x<numPatches;x++)
  245.             {
  246.                 RECT r = {x * (m_size.x - 1) / (float)numPatches, 
  247.                         y * (m_size.y - 1) / (float)numPatches, 
  248.                         (x+1) * (m_size.x - 1) / (float)numPatches,
  249.                         (y+1) * (m_size.y - 1) / (float)numPatches};
  250.                         
  251.                 PATCH *p = new PATCH();
  252.                 p->CreateMesh(*this, r, m_pDevice);
  253.                 m_patches.push_back(p);
  254.             }
  255.     }
  256.     catch(...)
  257.     {
  258.         debug.Print("Error in TERRAIN::CreatePatches()");
  259.     }
  260. }
  261.  
  262. void TERRAIN::CalculateAlphaMaps()
  263. {
  264.     //Clear old alpha maps
  265.     if(m_pAlphaMap != NULL)
  266.         m_pAlphaMap->Release();
  267.  
  268.     //Create new alpha map
  269.     D3DXCreateTexture(m_pDevice, 128, 128, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &m_pAlphaMap);
  270.  
  271.     //Lock the texture
  272.     D3DLOCKED_RECT sRect;
  273.     m_pAlphaMap->LockRect(0, &sRect, NULL, NULL);
  274.     BYTE *bytes = (BYTE*)sRect.pBits;
  275.     memset(bytes, 0, 128*sRect.Pitch);        //Clear texture to black
  276.  
  277.     for(int i=0;i<m_diffuseMaps.size();i++)
  278.         for(int y=0;y<sRect.Pitch / 4;y++)
  279.             for(int x=0;x<sRect.Pitch / 4;x++)
  280.             {
  281.                 int terrain_x = m_size.x * (x / (float)(sRect.Pitch / 4.0f));
  282.                 int terrain_y = m_size.y * (y / (float)(sRect.Pitch / 4.0f));
  283.                 MAPTILE *tile = GetTile(terrain_x, terrain_y);
  284.  
  285.                 if(tile != NULL && tile->m_type == i)
  286.                     bytes[y * sRect.Pitch + x * 4 + i] = 255;
  287.             }
  288.  
  289.     //Unlock the texture
  290.     m_pAlphaMap->UnlockRect(0);
  291.     
  292.     //D3DXSaveTextureToFile("alpha.bmp", D3DXIFF_BMP, m_pAlphaMap, NULL);
  293. }
  294.  
  295. void TERRAIN::AddObject(int type, INTPOINT mappos)
  296. {
  297.     D3DXVECTOR3 pos = D3DXVECTOR3(mappos.x, m_pHeightMap->GetHeight(mappos), -mappos.y);    
  298.     D3DXVECTOR3 rot = D3DXVECTOR3((rand()%1000 / 1000.0f) * 0.13f, (rand()%1000 / 1000.0f) * 3.0f, (rand()%1000 / 1000.0f) * 0.13);
  299.  
  300.     float sca_xz = (rand()%1000 / 1000.0f) * 0.5f + 0.5f;
  301.     float sca_y = (rand()%1000 / 1000.0f) * 1.0f + 0.5f;
  302.     D3DXVECTOR3 sca = D3DXVECTOR3(sca_xz, sca_y, sca_xz);
  303.  
  304.     m_objects.push_back(OBJECT(type, mappos, pos, rot, sca));
  305. }
  306.  
  307. void TERRAIN::Render(CAMERA &camera)
  308. {
  309.     //Set render states        
  310.     m_pDevice->SetRenderState(D3DRS_LIGHTING, false);
  311.     m_pDevice->SetRenderState(D3DRS_ZWRITEENABLE, true);    
  312.     
  313.     m_pDevice->SetTexture(0, m_pAlphaMap);
  314.     m_pDevice->SetTexture(1, m_diffuseMaps[0]);        //Grass
  315.     m_pDevice->SetTexture(2, m_diffuseMaps[1]);        //Mountain
  316.     m_pDevice->SetTexture(3, m_diffuseMaps[2]);        //Snow
  317.     m_pDevice->SetMaterial(&m_mtrl);
  318.  
  319.     D3DXMATRIX world;
  320.     D3DXMatrixIdentity(&world);
  321.     m_pDevice->SetTransform(D3DTS_WORLD, &world);
  322.  
  323.     m_terrainPS.Begin();
  324.         
  325.     for(int p=0;p<m_patches.size();p++)
  326.         if(!camera.Cull(m_patches[p]->m_BBox))
  327.             m_patches[p]->Render();
  328.  
  329.     m_terrainPS.End();    
  330.  
  331.     m_pDevice->SetTexture(1, NULL);
  332.     m_pDevice->SetTexture(2, NULL);
  333.     m_pDevice->SetTexture(3, NULL);
  334.  
  335.     //Render Objects
  336.     for(int i=0;i<m_objects.size();i++)
  337.         if(!camera.Cull(m_objects[i].m_BBox))
  338.             m_objects[i].Render();
  339. }
  340.  
  341. bool TERRAIN::Within(INTPOINT p)
  342. {
  343.     return p.x >= 0 && p.y >= 0 && p.x < m_size.x && p.y < m_size.y;
  344. }
  345.  
  346. void TERRAIN::InitPathfinding()
  347. {
  348.     try
  349.     {
  350.         //Read maptile heights & types from heightmap
  351.         for(int y=0;y<m_size.y;y++)
  352.             for(int x=0;x<m_size.x;x++)
  353.             {
  354.                 MAPTILE *tile = GetTile(x, y);
  355.                 if(m_pHeightMap != NULL)tile->m_height = m_pHeightMap->GetHeight(x, y);
  356.                 tile->m_mappos = INTPOINT(x, y);
  357.                 
  358.                 if(tile->m_height < 0.3f)         tile->m_type = 0;    //Grass
  359.                 else if(tile->m_height < 7.0f) tile->m_type = 1;    //Stone
  360.                 else                         tile->m_type = 2;    //Snow
  361.             }
  362.  
  363.         //Calculate tile cost as a function of the height variance
  364.         for(int y=0;y<m_size.y;y++)        
  365.             for(int x=0;x<m_size.x;x++)
  366.             {
  367.                 MAPTILE *tile = GetTile(x, y);
  368.  
  369.                 if(tile != NULL)
  370.                 {
  371.                     //Possible neighbors
  372.                     INTPOINT p[] = {INTPOINT(x-1, y-1), INTPOINT(x, y-1), INTPOINT(x+1, y-1),
  373.                                     INTPOINT(x-1, y),                      INTPOINT(x+1, y),
  374.                                     INTPOINT(x-1, y+1), INTPOINT(x, y+1), INTPOINT(x+1, y+1)};
  375.  
  376.                     float variance = 0.0f;
  377.                     int nr = 0;
  378.  
  379.                     //For each neighbor
  380.                     for(int i=0;i<8;i++)    
  381.                         if(Within(p[i]))
  382.                         {
  383.                             MAPTILE *neighbor = GetTile(p[i]);
  384.  
  385.                             if(neighbor != NULL)
  386.                             {
  387.                                 float v = neighbor->m_height - tile->m_height;
  388.                                 variance += (v * v);
  389.                                 nr++;
  390.                             }
  391.                         }
  392.  
  393.                     //Cost = height variance
  394.                     variance /= (float)nr;
  395.                     tile->m_cost = variance + 0.1f;
  396.                     if(tile->m_cost > 1.0f)tile->m_cost = 1.0f;
  397.  
  398.                     //If the tile cost is less than 1.0f, then we can walk on the tile
  399.                     tile->m_walkable = tile->m_cost < 0.5f;
  400.                 }
  401.             }
  402.  
  403.         //Make maptiles with objects on them not walkable
  404.         for(int i=0;i<m_objects.size();i++)
  405.         {
  406.             MAPTILE *tile = GetTile(m_objects[i].m_mappos);
  407.             if(tile != NULL)
  408.             {
  409.                 tile->m_walkable = false;
  410.                 tile->m_cost = 1.0f;
  411.             }
  412.         }
  413.  
  414.         //Connect maptiles using the neightbors[] pointers
  415.         for(int y=0;y<m_size.y;y++)        
  416.             for(int x=0;x<m_size.x;x++)
  417.             {
  418.                 MAPTILE *tile = GetTile(x, y);
  419.                 if(tile != NULL && tile->m_walkable)
  420.                 {
  421.                     //Clear old connections
  422.                     for(int i=0;i<8;i++)
  423.                         tile->m_pNeighbors[i] = NULL;
  424.  
  425.                     //Possible neighbors
  426.                     INTPOINT p[] = {INTPOINT(x-1, y-1), INTPOINT(x, y-1), INTPOINT(x+1, y-1),
  427.                                     INTPOINT(x-1, y),                      INTPOINT(x+1, y),
  428.                                     INTPOINT(x-1, y+1), INTPOINT(x, y+1), INTPOINT(x+1, y+1)};
  429.  
  430.                     //For each neighbor
  431.                     for(int i=0;i<8;i++)    
  432.                         if(Within(p[i]))
  433.                         {
  434.                             MAPTILE *neighbor = GetTile(p[i]);
  435.  
  436.                             //Connect tiles if the neighbor is walkable
  437.                             if(neighbor != NULL && neighbor->m_walkable)
  438.                                 tile->m_pNeighbors[i] = neighbor;
  439.                         }
  440.                 }
  441.             }
  442.  
  443.         CreateTileSets();
  444.     }
  445.     catch(...)
  446.     {
  447.         debug.Print("Error in InitPathfinding()");
  448.     }    
  449. }
  450.  
  451. void TERRAIN::CreateTileSets()
  452. {
  453.     try
  454.     {
  455.         int setNo = 0;
  456.         for(int y=0;y<m_size.y;y++)        //Set a unique set for each tile...
  457.             for(int x=0;x<m_size.x;x++)
  458.                 m_pMapTiles[x + y * m_size.x].m_set = setNo++;
  459.  
  460.         bool changed = true;
  461.         while(changed)
  462.         {
  463.             changed = false;
  464.  
  465.             for(int y=0;y<m_size.y;y++)
  466.                 for(int x=0;x<m_size.x;x++)
  467.                 {
  468.                     MAPTILE *tile = GetTile(x, y);
  469.  
  470.                     //Find the lowest set of a neighbor
  471.                     if(tile != NULL && tile->m_walkable)
  472.                     {
  473.                         for(int i=0;i<8;i++)
  474.                             if(tile->m_pNeighbors[i] != NULL &&
  475.                                 tile->m_pNeighbors[i]->m_walkable &&
  476.                                 tile->m_pNeighbors[i]->m_set < tile->m_set)
  477.                             {
  478.                                 changed = true;
  479.                                 tile->m_set = tile->m_pNeighbors[i]->m_set;
  480.                             }
  481.                     }
  482.                 }
  483.         }
  484.     }
  485.     catch(...)
  486.     {
  487.         debug.Print("Error in TERRAIN::CreateTileSets()");
  488.     }
  489. }
  490.  
  491. float H(INTPOINT a, INTPOINT b)
  492. {
  493.     //return abs(a.x - b.x) + abs(a.y - b.y);
  494.     return a.Distance(b);
  495. }
  496.  
  497. std::vector<INTPOINT> TERRAIN::GetPath(INTPOINT start, INTPOINT goal)
  498. {
  499.     try
  500.     {
  501.         //Check that the two points are within the bounds of the map
  502.         MAPTILE *startTile = GetTile(start);
  503.         MAPTILE *goalTile = GetTile(goal);
  504.  
  505.         if(!Within(start) || !Within(goal) || start == goal || startTile == NULL || goalTile == NULL)
  506.             return std::vector<INTPOINT>();
  507.  
  508.         //Check if a path exists
  509.         if(!startTile->m_walkable || !goalTile->m_walkable || startTile->m_set != goalTile->m_set)
  510.             return std::vector<INTPOINT>();
  511.  
  512.         //Init Search
  513.         long numTiles = m_size.x * m_size.y;
  514.         for(long l=0;l<numTiles;l++)
  515.         {
  516.             m_pMapTiles[l].f = m_pMapTiles[l].g = INT_MAX;        //Clear F,G
  517.             m_pMapTiles[l].open = m_pMapTiles[l].closed = false;    //Reset Open and Closed
  518.         }
  519.  
  520.         std::vector<MAPTILE*> open;                //Create Our Open list
  521.         startTile->g = 0;                        //Init our starting point (SP)
  522.         startTile->f = H(start, goal);
  523.         startTile->open = true;
  524.         open.push_back(startTile);                //Add SP to the Open list
  525.  
  526.         bool found = false;                    // Search as long as a path hasnt been found,
  527.         while(!found && !open.empty())        // or there is no more tiles to search
  528.         {                                                
  529.             MAPTILE * best = open[0];        // Find the best tile (i.e. the lowest F value)
  530.             int bestPlace = 0;
  531.             for(int i=1;i<open.size();i++)
  532.                 if(open[i]->f < best->f)
  533.                 {
  534.                     best = open[i];
  535.                     bestPlace = i;
  536.                 }
  537.             
  538.             if(best == NULL)break;            //No path found
  539.  
  540.             open[bestPlace]->open = false;
  541.             open.erase(&open[bestPlace]);    // Take the best node out of the Open list
  542.  
  543.             if(best->m_mappos == goal)        //If the goal has been found
  544.             {
  545.                 std::vector<INTPOINT> p, p2;
  546.                 MAPTILE *point = best;
  547.  
  548.                 while(point->m_mappos != start)    // Generate path
  549.                 {
  550.                     p.push_back(point->m_mappos);
  551.                     point = point->m_pParent;
  552.                 }
  553.  
  554.                 for(int i=p.size()-1;i!=0;i--)    // Reverse path
  555.                     p2.push_back(p[i]);
  556.                 p2.push_back(goal);
  557.                 return p2;
  558.             }
  559.             else
  560.             {
  561.                 for(i=0;i<8;i++)                    // otherwise, check the neighbors of the
  562.                     if(best->m_pNeighbors[i] != NULL)    // best tile
  563.                     {
  564.                         bool inList = false;        // Generate new G and F value
  565.                         float newG = best->g + 1.0f;
  566.                         float d = H(best->m_mappos, best->m_pNeighbors[i]->m_mappos);
  567.                         float newF = newG + H(best->m_pNeighbors[i]->m_mappos, goal) + best->m_pNeighbors[i]->m_cost * 5.0f * d;
  568.  
  569.                         if(best->m_pNeighbors[i]->open || best->m_pNeighbors[i]->closed)
  570.                         {
  571.                             if(newF < best->m_pNeighbors[i]->f)    // If the new F value is lower
  572.                             {
  573.                                 best->m_pNeighbors[i]->g = newG;    // update the values of this tile
  574.                                 best->m_pNeighbors[i]->f = newF;
  575.                                 best->m_pNeighbors[i]->m_pParent = best;                                
  576.                             }
  577.                             inList = true;
  578.                         }
  579.  
  580.                         if(!inList)            // If the neighbor tile isn't in the Open or Closed list
  581.                         {
  582.                             best->m_pNeighbors[i]->f = newF;        //Set the values
  583.                             best->m_pNeighbors[i]->g = newG;
  584.                             best->m_pNeighbors[i]->m_pParent = best;
  585.                             best->m_pNeighbors[i]->open = true;
  586.                             open.push_back(best->m_pNeighbors[i]);    //Add it to the open list    
  587.                         }
  588.                     }
  589.  
  590.                 best->closed = true;        //The best tile has now been searched, add it to the Closed list
  591.             }
  592.         }
  593.  
  594.         return std::vector<INTPOINT>();        //No path found, return an empty path
  595.         
  596.     }
  597.     catch(...)
  598.     {
  599.         debug.Print("Error in TERRAIN::GetPath()");
  600.         return std::vector<INTPOINT>();
  601.     }
  602. }
  603.  
  604. MAPTILE* TERRAIN::GetTile(int x, int y)
  605. {
  606.     if(m_pMapTiles == NULL)return NULL;
  607.  
  608.     try
  609.     {
  610.         return &m_pMapTiles[x + y * m_size.x];
  611.     }
  612.     catch(...)
  613.     {
  614.         return NULL;
  615.     }
  616. }
  617.  
  618. void TERRAIN::SaveTerrain(char fileName[])
  619. {
  620.     try
  621.     {
  622.         std::ofstream out(fileName, std::ios::binary);        //Binary format
  623.  
  624.         if(out.good())
  625.         {
  626.             out.write((char*)&m_size, sizeof(INTPOINT));    //Write map size
  627.  
  628.             //Write all the maptile information needed to recreate the map
  629.             for(int y=0;y<m_size.y;y++)
  630.                 for(int x=0;x<m_size.x;x++)
  631.                 {
  632.                     MAPTILE *tile = GetTile(x, y);
  633.                     out.write((char*)&tile->m_type, sizeof(int));            //type
  634.                     out.write((char*)&tile->m_height, sizeof(float));        //Height
  635.                 }
  636.  
  637.             //Write all the objects
  638.             int numObjects = m_objects.size();
  639.             out.write((char*)&numObjects, sizeof(int));     //Num Objects
  640.             for(int i=0;i<m_objects.size();i++)
  641.             {
  642.                 out.write((char*)&m_objects[i].m_type, sizeof(int));                            //type
  643.                 out.write((char*)&m_objects[i].m_mappos, sizeof(INTPOINT));                    //mappos
  644.                 out.write((char*)&m_objects[i].m_meshInstance.m_pos, sizeof(D3DXVECTOR3));    //Pos
  645.                 out.write((char*)&m_objects[i].m_meshInstance.m_rot, sizeof(D3DXVECTOR3));    //Rot
  646.                 out.write((char*)&m_objects[i].m_meshInstance.m_sca, sizeof(D3DXVECTOR3));    //Sca
  647.             }
  648.         }
  649.  
  650.         out.close();
  651.     }
  652.     catch(...)
  653.     {
  654.         debug.Print("Error in TERRAIN::SaveTerrain()");
  655.     }
  656. }
  657.  
  658. void TERRAIN::LoadTerrain(char fileName[])
  659. {
  660.     try
  661.     {
  662.         std::ifstream in(fileName, std::ios::binary);        //Binary format
  663.  
  664.         if(in.good())
  665.         {
  666.             Release();    //Release all terrain resources
  667.  
  668.             in.read((char*)&m_size, sizeof(INTPOINT));    //read map size
  669.         
  670.             if(m_pMapTiles != NULL)    //Clear old maptiles
  671.                 delete [] m_pMapTiles;
  672.  
  673.             //Create new maptiles
  674.             m_pMapTiles = new MAPTILE[m_size.x * m_size.y];
  675.             memset(m_pMapTiles, 0, sizeof(MAPTILE)*m_size.x*m_size.y);
  676.  
  677.  
  678.             //Read the maptile information
  679.             for(int y=0;y<m_size.y;y++)
  680.                 for(int x=0;x<m_size.x;x++)
  681.                 {
  682.                     MAPTILE *tile = GetTile(x, y);
  683.                     in.read((char*)&tile->m_type, sizeof(int));            //type
  684.                     in.read((char*)&tile->m_height, sizeof(float));        //Height
  685.                 }
  686.  
  687.             //Read number of objects
  688.             int numObjects = 0;
  689.             in.read((char*)&numObjects, sizeof(int));
  690.             for(int i=0;i<numObjects;i++)
  691.             {
  692.                 int type = 0;
  693.                 INTPOINT mp;
  694.                 D3DXVECTOR3 p, r, s;
  695.  
  696.                 in.read((char*)&type, sizeof(int));            //type
  697.                 in.read((char*)&mp, sizeof(INTPOINT));        //mappos
  698.                 in.read((char*)&p, sizeof(D3DXVECTOR3));    //Pos
  699.                 in.read((char*)&r, sizeof(D3DXVECTOR3));    //Rot
  700.                 in.read((char*)&s, sizeof(D3DXVECTOR3));    //Sca
  701.  
  702.                 m_objects.push_back(OBJECT(type, mp, p, r, s));
  703.             }
  704.  
  705.             //Recreate Terrain
  706.             InitPathfinding();
  707.             CreatePatches(3);
  708.             CalculateAlphaMaps();
  709.         }
  710.  
  711.         in.close();
  712.     }
  713.     catch(...)
  714.     {
  715.         debug.Print("Error in TERRAIN::LoadTerrain()");
  716.     }
  717. }
  718.  
  719. D3DXVECTOR3 TERRAIN::GetWorldPos(INTPOINT mappos)
  720. {
  721.     if(!Within(mappos))return D3DXVECTOR3(0, 0, 0);
  722.     MAPTILE *tile = GetTile(mappos);
  723.     return D3DXVECTOR3(mappos.x, tile->m_height, -mappos.y);
  724. }